package com.moleq.device;

import jp.co.casio.caios.framework.device.DeviceCommon;
import jp.co.casio.caios.framework.device.SerialCom;
import android.os.Handler;
import android.os.Message;


public class BaseScale implements IScale {

	private ScaleSetting mScaleSetting;
	private LocalDevice mDeviceState;
	private boolean mWeightSwitch;
	private boolean mWeightPaused = false;
	private Thread mWeightThread = null;
	private String mWeightCmd;
	private String mCancelCmd = "";
//	private String mWeightCmdEndChar;
//	private String mCancelCmdEndChar;
	private String mReceiveEndChar;
	private String mDataFormatStartIdx;
	private String mDataFormatLen;
	private IDeviceEvent mListener;
	private SerialCom mSerialCom;
	private int mPort;
	private int mBaudRate;
	private int mBitLen;
	private int mParityBit;
	private int mStopBit;
	
	public static final int SCALE_RECEIVED = 111;
	public static final int SCALE_TIME_OUT = 199;
	
	private final Handler mWeightHandler = new Handler() {

	

		@Override
		public void handleMessage(Message msg) {
			
			switch(msg.what){
				case SCALE_RECEIVED:
//					String resData = msg.obj.toString().trim();
//					if(resData.length() >= mDataFormatStartIdx -1 +mDataFormatLen){
//						
//						String sWeight  = resData.substring(mDataFormatStartIdx,mDataFormatStartIdx + mDataFormatLen);
//						if(TextUtils.isDigitsOnly(sWeight)){
//							mListener.onWeightEvent(Integer.valueOf(sWeight));
//						}
//						
//					}
					break;
				case SCALE_TIME_OUT:
					mListener.onTimeOutEvent();
					break;
			}

		}
		
	};
	private int mReceiveDataStartIdx;
	private int mReceiveDataLen;
	private boolean mInvalidDataFormat;
	private int mDivisor;
	private boolean mIsConnected;
	


	// resd weight buffer
	protected void readWeightBuffer(double timeout) {

		double cnt = timeout * 1000 / 200;
		double k = 0;
		String result;

		while (mWeightSwitch) {

			if (!mWeightPaused) {

				if (k < cnt) {

					int rev = 0;

					result = "";

					byte[] tmpbuffer = new byte[1024];
					rev = mSerialCom.readData(tmpbuffer);
					
					while (rev > 0) {
						result += new String(tmpbuffer);
						tmpbuffer = new byte[1024];
						rev = mSerialCom.readData(tmpbuffer);
					}
					
					
					if( !result.trim().equals("")){
						mWeightSwitch = false;
						k = cnt;
						Message message = mWeightHandler.obtainMessage(SCALE_RECEIVED,
								result);
						mWeightHandler.sendMessage(message);
						
					} else {
						k++;

						try {
							Thread.sleep(300);
						} catch (InterruptedException ex) {
							ex.printStackTrace();
						}
					}

				} else {
					onDisableScale();
					// clearBuffer();
					Message message = mWeightHandler.obtainMessage(SCALE_TIME_OUT, "");
					mWeightHandler.sendMessage(message);

				}
			}
		}
	}

	@Override
	public LocalDevice getState() {
		return this.mDeviceState;
	}

	@Override
	public void onDisconnect() {
		if (this.mDeviceState == LocalDevice.OPEN_STATE) {
			if (mWeightSwitch) {
				mWeightSwitch = false;

				try {
					Thread.sleep(500);
				} catch (InterruptedException ex) {
					ex.printStackTrace();
				}
			}

			if (mSerialCom != null) {
				mSerialCom.disconnectCom();
				mSerialCom.close();
				mSerialCom = null;
				mDeviceState = LocalDevice.CLOSE_STATE;
				mIsConnected = false;
			}
		}

	}

	@Override
	public void onConnect() {
		if (mSerialCom == null) {
			mSerialCom = new SerialCom();
		}


		boolean result = false;
		int response = 0;

		response = mSerialCom.open(mPort, 
				DeviceCommon.DEVICE_MODE_COMMON,
				DeviceCommon.DEVICE_HOST_LOCALHOST);
		if (response != 0) {

		
			mListener.onErrorEvent("Faild to open.");
			this.mDeviceState = LocalDevice.CLOSE_STATE;
			return;
		}

//		result = mSerialCom.connectCom(SerialCom.SERIAL_BOUDRATE_9600,
//				SerialCom.SERIAL_BITLEN_7, 
//				SerialCom.SERIAL_PARITY_EVEN,
//				SerialCom.SERIAL_STOP_1, 
//				SerialCom.SERIAL_FLOW_NON);
		
		result = mSerialCom.connectCom(mBaudRate, mBitLen, mParityBit,mStopBit, 
				SerialCom.SERIAL_FLOW_NON);
		
		if (result != true) {
			
			mListener.onErrorEvent("Faild to connect serial port");

			this.mDeviceState = LocalDevice.CLOSE_STATE;
			mIsConnected = false;
			return;
		}

		mSerialCom.setControl(SerialCom.SERIAL_IO_CTS);
		mSerialCom.setControl(SerialCom.SERIAL_IO_RTS);

		this.mDeviceState = LocalDevice.OPEN_STATE;
		mIsConnected = true;

	}

	@Override
	public void setCallbackEvent(IDeviceEvent impl) {
		mListener = impl;

	}

	@Override
	public void setComPort(int comPort) {
		// TODO Auto-generated method stub

	}

	@Override
	public String getScanCode() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void getWeight(final double timeout) {
		
		sendCmd(mWeightCmd);

		mWeightSwitch = true;
		mWeightPaused = false;
		if (mWeightThread == null) {
			mWeightThread = new Thread(new Runnable() {
				@Override
				public void run() {

					readWeightBuffer(timeout);

				}
			});

			mWeightThread.setDaemon(true);
			mWeightThread.start();
		}

		if (mWeightThread.getState() != Thread.State.TERMINATED) {

		} else {

			mWeightThread = new Thread(new Runnable() {
				@Override
				public void run() {

					readWeightBuffer(timeout);

				}
			});
			mWeightThread.setDaemon(true);
			mWeightThread.start();
		}
	}

	@Override
	public String receiveData() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void sendCmd(String strCommand) {
		try {
			int response = 0;
			byte[] bCmd = strCommand.getBytes();

			if (mSerialCom != null) {
				response = mSerialCom.writeData(bCmd, bCmd.length);
			}
			if (response != 0) {
				mListener.onErrorEvent("Serial write data error.");
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}

	@Override
	public void onEnableScale() {
		mWeightPaused = false;
		mWeightSwitch = true;

	}

	@Override
	public void onDisableScale() {
		mWeightPaused = true;
		mWeightSwitch = false;
		
		if(! ( mCancelCmd.equals("") ||  mCancelCmd.equals("NONE")))
			sendCmd(mCancelCmd);
			
		
		
	
	}

	@Override
	public void setScaleSetting(ScaleSetting setting) {
		mScaleSetting = setting;
		
		 
//		 mPort = setting.getPort();
//		 mBaudRate = Integer.valueOf(setting.getBaud());
//		 mBitLen = setting.getDataBits();
//		 mParityBit = Integer.valueOf(setting.getParity());
//		 mStopBit = setting.getStopBits();
		 
		 
		// set port
		switch (setting.getPort()) {
		case 1:
			mPort = SerialCom.SERIAL_TYPE_COM1;
			break;
		case 2:
			mPort = SerialCom.SERIAL_TYPE_COM2;
			break;
		case 3:
			mPort = SerialCom.SERIAL_TYPE_COM3;
			break;
		case 4:
			mPort = SerialCom.SERIAL_TYPE_COM4;
			break;
		case 5:
			mPort = SerialCom.SERIAL_TYPE_COM5;
			break;

		}

		// set baud rate
		String baudrate = setting.getBaud();
		if (baudrate.equals("38400")) {
			mBaudRate = SerialCom.SERIAL_BOUDRATE_38400;
		} else if (baudrate.equals("19200")) {
			mBaudRate = SerialCom.SERIAL_BOUDRATE_19200;
		} else if (baudrate.equals("9600")) {
			mBaudRate = SerialCom.SERIAL_BOUDRATE_9600;
		} else if (baudrate.equals("4800")) {
			mBaudRate = SerialCom.SERIAL_BOUDRATE_4800;
		} else if (baudrate.equals("2400")) {
			mBaudRate = SerialCom.SERIAL_BOUDRATE_2400;
		} else if (baudrate.equals("1200")) {
			mBaudRate = SerialCom.SERIAL_BOUDRATE_1200;
		}

		// set bit len
		switch (setting.getDataBits()) {
		case 7:
			mBitLen = SerialCom.SERIAL_BITLEN_7;
			break;
		case 8:
			mBitLen = SerialCom.SERIAL_BITLEN_8;
			break;
		}

		// set parity
		String parity = setting.getParity();
		if (parity.equals("E")) {
			mParityBit = SerialCom.SERIAL_PARITY_EVEN;
		} else if (parity.equals("N")) {
			mParityBit = SerialCom.SERIAL_PARITY_NON;
		} else if (parity.equals("O")) {
			mParityBit = SerialCom.SERIAL_PARITY_ODD;
		}

		// set Stop Bit
		switch (setting.getStopBits()) {
		case 1:
			mStopBit = SerialCom.SERIAL_STOP_1;
			break;
		case 2:
			mStopBit = SerialCom.SERIAL_STOP_2;
			break;

		}
		
		//mWeightCmd = "W{13}"; 
//		"{2}KK{5}"  = char(2)+K+K+char(5) 
//		"{6}{8}MING{6}{7}" = char(6)+char(8)+M+I+N+G+char(6) +char(7)
//		"{8}MI NG{6}"     = char(8)+M+I
/*
		mWeightCmd = "W{13}";
		Log.i("BaseScale",mWeightCmd +  "  ==  " + DeviceCmdUtil.getStringCommand(mWeightCmd));
		mWeightCmd = DeviceCmdUtil.getStringCommand(mWeightCmd);
		
		mWeightCmd = "{2}KK{5}";
		Log.i("BaseScale",mWeightCmd +  "  ==  " + DeviceCmdUtil.getStringCommand(mWeightCmd));
		mWeightCmd = DeviceCmdUtil.getStringCommand(mWeightCmd);
		
		mWeightCmd = "{6}{8}MING{6}{7}";
		Log.i("BaseScale",mWeightCmd +  "  ==  " + DeviceCmdUtil.getStringCommand(mWeightCmd));
		mWeightCmd = DeviceCmdUtil.getStringCommand(mWeightCmd);
		
		mWeightCmd = "{8}MI NG{6}";
		Log.i("BaseScale",mWeightCmd +  "  ==  " + DeviceCmdUtil.getStringCommand(mWeightCmd));
		mWeightCmd = DeviceCmdUtil.getStringCommand(mWeightCmd);
		
		mWeightCmd = "{8}MING{6}KK";
		Log.i("BaseScale",mWeightCmd +  "  ==  " + DeviceCmdUtil.getStringCommand(mWeightCmd));
		mWeightCmd = DeviceCmdUtil.getStringCommand(mWeightCmd);
		*/

		mWeightCmd = DeviceUtil.getStringCommand(setting.getWeightCmd());
//		mWeightCmdEndChar = DeviceCmdUtil.getEndChar(setting.getWeightCmd());
		 
		mCancelCmd = DeviceUtil.getStringCommand(setting.getCancelCmd());
//		mCancelCmdEndChar =  DeviceCmdUtil.getEndChar(setting.getCancelCmd());
		
		mReceiveEndChar = DeviceUtil.getEndChar(setting.getEndChar());

		// set cut buffer
		String[] sdata = setting.getDataFormat().split(",");

		mInvalidDataFormat = true;
		mDataFormatStartIdx = "";
		mDataFormatLen = "";
		if (sdata.length == 2 ) {
			
			mDataFormatStartIdx = sdata[0].trim();
			mDataFormatLen =  sdata[1].trim();
			
			if(DeviceUtil.isNumeric(mDataFormatStartIdx) && DeviceUtil.isNumeric(mDataFormatLen)){
				mInvalidDataFormat = false;
				mReceiveDataStartIdx = Integer.valueOf(mDataFormatStartIdx);
				mReceiveDataLen = Integer.valueOf(mDataFormatLen);
			}
			
		} 
		
		// set divisor
	    mDivisor = setting.getDivisor();
	    if(mDivisor == 0) mDivisor = 1;
	
		
	}
		
		
	

	@Override
	public double getWeight() {
		double dResult = 0;
		String sDeviceBuffer= "";
		
		try{
//			sendCmd(mWeightCmd + mWeightCmdEndChar);
			sendCmd(mWeightCmd );
			
			Thread.sleep(400);
			
			int rev = 0;

			byte[] tmpbuffer = new byte[1024];
			rev = mSerialCom.readData(tmpbuffer);

			while (rev > 0) {
				sDeviceBuffer += new String(tmpbuffer);

				tmpbuffer = new byte[1024];
				rev = mSerialCom.readData(tmpbuffer);
			}

			sDeviceBuffer = sDeviceBuffer.trim();
//			if(TextUtils.isDigitsOnly(sDeviceBuffer)){
//				dResult  = Double.valueOf(sDeviceBuffer);
//			}
			
			dResult = getReceiveWeight(sDeviceBuffer);
			
			if(dResult == 0){
				if(!(mCancelCmd.equals("") && mCancelCmd != "NONE")){
//					sendCmd(mCancelCmd + mCancelCmdEndChar);
					sendCmd(mCancelCmd);
					onClearBuffer();
				}
			}
			
			return dResult;
		}catch(Exception ex){
			ex.printStackTrace();
			
		}finally{
			
			return dResult;
		}
	}
	
	private double getReceiveWeight(String resData){
		
		double result = 0;
		
		if(mInvalidDataFormat){
			result = Double.valueOf(resData);
		}else{
			
			int formatLen = mReceiveDataStartIdx + mReceiveDataLen;
			int recDataLen = resData.length();
			String tmp = "0";
			
			if(recDataLen > mReceiveDataStartIdx ){
				if(recDataLen > formatLen){
					tmp = resData.substring(mReceiveDataStartIdx - 1, formatLen);
				}else{
					tmp = resData.substring(mReceiveDataStartIdx - 1, recDataLen);
				}
			}
//			else{
//				tmp = "-1";
//			}
			
			
			result = Double.valueOf(tmp);
			result = result / mDivisor;
		}
		return result;
		
	}
	
	@Override
	public void onClearBuffer() {
		
		try {
			Thread.sleep(400);
			mSerialCom.readData(new byte[1024]);
		} catch (InterruptedException ex) {
			ex.printStackTrace();
		}
			
		
	}

	@Override
	public boolean isConnected() {
		// TODO Auto-generated method stub
		return mIsConnected;
	}

}
